package com.fishingwithme.android.data.network


import com.fishingwithme.android.data.local.PreferencesManager
import com.fishingwithme.android.data.model.CircleMessage
import com.fishingwithme.android.data.model.CircleMessageDeserializer
import com.google.gson.GsonBuilder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Named
import javax.inject.Qualifier
import javax.inject.Singleton

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class AuthInterceptor

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class ResponseInterceptor

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

     const val BASE_URL = "http://192.168.101.92:8081" // API server URL
     const val IMAGE_BASE_URL = "http://192.168.101.110" // Image server URL


    @Provides
    @Singleton
    fun provideJson(): Json = Json {
        ignoreUnknownKeys = true
        coerceInputValues = true
        isLenient = true
    }

    @Provides
    @Singleton
    @AuthInterceptor
    fun provideAuthInterceptor(preferencesManager: PreferencesManager): Interceptor =
        Interceptor { chain ->
            val originalRequest = chain.request()
            val newRequest = originalRequest.newBuilder()
                .apply {
                    // Add common headers
                    addHeader("Content-Type", "application/json")
                    addHeader("Accept", "application/json")

                    // Check if token is needed based on the Need-Token header
                    val needToken = originalRequest.header("Need-Token")?.toBoolean() ?: true
                    if (needToken) {
                        // Get token from preferences (using runBlocking since Interceptor is not suspend)
                        val token = runBlocking {
                            preferencesManager.getAccessToken().firstOrNull()
                        }
                        token?.let {
                            addHeader("Authorization", "Bearer $it")
                        }
                    }
                }
                .build()
            chain.proceed(newRequest)
        }

    @Provides
    @Singleton
    fun provideLoggingInterceptor(): HttpLoggingInterceptor =
        HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.BODY
        }

    @Provides
    @Singleton
    @ResponseInterceptor
    fun provideResponseInterceptor(preferencesManager: PreferencesManager): Interceptor =
        Interceptor { chain ->
            val response = chain.proceed(chain.request())

            // Check if response is 401 Unauthorized
            if (response.code == 401) {
                // Clear user token
                runBlocking {
                    preferencesManager.clearAccessToken()
                    preferencesManager.clearLoginUser()
                }
            }

            response
        }

    @Provides
    @Singleton
    fun provideOkHttpClient(
        @AuthInterceptor authInterceptor: Interceptor,
        @ResponseInterceptor responseInterceptor: Interceptor,
        loggingInterceptor: HttpLoggingInterceptor
    ): OkHttpClient = OkHttpClient.Builder()
        .addInterceptor(authInterceptor)
        .addInterceptor(responseInterceptor)
        .addInterceptor(loggingInterceptor)
        .addNetworkInterceptor(Interceptor { chain ->
            val request = chain.request()
            val response = chain.proceed(request)
            response
        })
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .build()

    @Provides
    @Singleton
    fun provideGson(): com.google.gson.Gson = GsonBuilder()
        .registerTypeAdapter(
            CircleMessage::class.java,
            CircleMessageDeserializer()
        )
        .create()

    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient, gson: com.google.gson.Gson): Retrofit =
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()

    @Provides
    @Singleton
    fun provideFishingApiService(retrofit: Retrofit): FishingApiService =
        retrofit.create(FishingApiService::class.java)

    @Provides
    @Singleton
    @Named("imageBaseUrl")
    fun provideImageBaseUrl(): String = IMAGE_BASE_URL
}